package cn.dengta.webapp.trade.model;

import java.util.*;

import cn.dengta.common.model.State;
import cn.dengta.common.model.ValueProxy;
import cn.dengta.context.model.LabelI18nProxy;
import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;
import me.codeplayer.util.Assert;
import org.apache.commons.lang3.StringUtils;

import static cn.dengta.common.model.State.PUBLIC;
import static cn.dengta.context.model.TradeEnumI18nKey.*;
import static cn.dengta.webapp.trade.model.TradeTypeCore.*;

/**
 * 与（虚拟）资金相关的业务交易类型枚举
 */
@Getter
public enum TradeType implements LabelI18nProxy<TradeType, String> {

	/*
	 * ============以下是【钻石交易】相关枚举============
	 */

	/**
	 * 充值钻石
	 */
	COIN_RECHARGE(TRADE_TYPE_COIN_RECHARGE, ADD_ACTIVE),
	/**
	 * 活动赠送钻石
	 */
	COIN_ADD_FREE(TRADE_TYPE_COIN_ADD_FREE, ADD_ACTIVE),
	/**
	 * 活动消耗钻石
	 */
	COIN_FOR_ACTIVITY(TRADE_TYPE_COIN_FOR_ACTIVITY, DEDUCT_ACTIVE),
	/**
	 * 搭讪消耗钻石
	 */
	COIN_FOR_GREET(TRADE_TYPE_COIN_FOR_GREET, DEDUCT_ACTIVE, anchorIncomeCore),
	/**
	 * 打赏消耗钻石
	 */
	COIN_FOR_DONATE(TRADE_TYPE_COIN_FOR_DONATE, DEDUCT_ACTIVE, anchorIncomeCore),

	/**
	 * 游戏消耗钻石
	 */
	COIN_FOR_GAME(TRADE_TYPE_COIN_FOR_GAME, DEDUCT_ACTIVE, true),

	/** 金币兑换消耗钻石 */
	COIN_FOR_EXCHANGE_GOLD(TRADE_TYPE_GOLD_EXCHANGE, DEDUCT_ACTIVE, true),

	/**
	 * 游戏奖励钻石
	 */
	COIN_FOR_GAME_REWARD(TRADE_TYPE_COIN_FOR_GAME_REWARD, ADD_ACTIVE, true),

	/** 背包活动礼物打赏 */
	COIN_FOR_GIFT_BAG(TRADE_TYPE_BAG_GIFT_FOR_DONATE, ADD_ACTIVE, anchorIncomeCore),
	/**
	 * 图文聊天消耗钻石
	 */
	COIN_FOR_MSG(TRADE_TYPE_COIN_FOR_MSG, DEDUCT_ACTIVE, anchorIncomeCore),
	/**
	 * 语音聊天消耗钻石
	 */
	COIN_FOR_AUDIO(TRADE_TYPE_COIN_FOR_AUDIO, DEDUCT_ACTIVE, anchorIncomeCore),
	/**
	 * 视频聊天消耗钻石
	 */
	COIN_FOR_VIDEO(TRADE_TYPE_COIN_FOR_VIDEO, DEDUCT_ACTIVE, anchorIncomeCore),
	/**
	 * 打赏礼物消耗钻石
	 */
	COIN_FOR_GIFT(TRADE_TYPE_COIN_FOR_GIFT, DEDUCT_ACTIVE, anchorIncomeCore),
	/**
	 * 直播间打赏礼物消耗钻石
	 */
	COIN_FOR_GIFT_LIVE(TRADE_TYPE_COIN_FOR_GIFT_LIVE, DEDUCT_ACTIVE, anchorIncomeCore),
	/**
	 * 发红包消耗钻石
	 */
	COIN_FOR_RED_PACKET(TRADE_TYPE_COIN_RED_PACKET, DEDUCT_ACTIVE, anchorIncomeCore),
	/**
	 * 红包过期，退回剩余钻石
	 */
	COIN_RED_PACKET_REFUND(TRADE_TYPE_COIN_RED_PACKET_REFUND, ADD_ACTIVE),
	/**
	 * 开通VIP消耗钻石
	 */
	COIN_FOR_VIP(TRADE_TYPE_COIN_FOR_VIP, DEDUCT_ACTIVE, true),
	/**
	 * 提高（被搭讪的）曝光率消耗钻石
	 */
	COIN_FOR_EXPOSE(TRADE_TYPE_COIN_FOR_EXPOSE, DEDUCT_ACTIVE, true),
	/**
	 * 缘分雷达消耗钻石
	 */
	COIN_FOR_FATE_RADAR(TRADE_TYPE_COIN_FOR_FATE_RADAR, DEDUCT_ACTIVE),
	/**
	 * Ai速配消耗钻石
	 */
	COIN_FOR_AI_SPEED(TRADE_TYPE_AI_SPEED, DEDUCT_ACTIVE),
	/**
	 * 退款后回收对应钻石
	 */
	COIN_FOR_REFUND(TRADE_TYPE_COIN_FOR_REFUND, DEDUCT_ACTIVE),
	/**
	 * 邀请奖励钻石
	 */
	COIN_AWARD_INVITE(TRADE_TYPE_COIN_AWARD_INVITE, ADD_ACTIVE),

	/**
	 * 后台增加 充值钻石
	 */
	COIN_SYSTEM_RECHARGE(TRADE_TYPE_COIN_SYSTEM_RECHARGE, ADD_ACTIVE),
	/**
	 * 后台减少钻石
	 */
	COIN_SYSTEM_DEDUCT(TRADE_TYPE_COIN_SYSTEM_DEDUCT, DEDUCT_ACTIVE, CoinConsumePriority.FREE_FIRST),

	/**
	 * 用户VIP每日赠送钻石
	 */
	COIN_VIP_DAY_GET(TRADE_TYPE_COIN_VIP_DAY_GET, ADD_ACTIVE),
	/**
	 * 搭讪钻石退回
	 */
	COIN_RETURN_GREET(TRADE_TYPE_COIN_RETURN_GREET, ADD_ACTIVE),
	/**
	 * 私信钻石退回
	 */
	COIN_RETURN_MSG(TRADE_TYPE_COIN_RETURN_MSG, ADD_ACTIVE),

	/**
	 * 积分兑换钻石
	 */
	COIN_BY_INTEGRAL(TRADE_TYPE_COIN_BY_INTEGRAL, ADD_ACTIVE),

	/**
	 * 用户VIP充值赠送钻石
	 */
	//COIN_VIP_RECHARGE_GET(TRADE_TYPE_COIN_VIP_RECHARGE_FREE, ADD_ACTIVE),
	/*
	 * ============以下是【积分交易】相关枚举============
	 */

	/**
	 * 获得积分收益（目前是先冻结）
	 * 第N天解冻之前的收益
	 */
	INTEGRAL_GAIN(TRADE_TYPE_INTEGRAL_GAIN, anchorIncomeCore, true),
	/**
	 * 获得用户分成积分收益（目前是先冻结）
	 * 第N天解冻之前的收益
	 */
	INTEGRAL_GAIN_EXTRACT_USER(TRADE_TYPE_INTEGRAL_GAIN_EXTRACT_USER, anchorIncomeCore, true),
	/**
	 * 积分解冻
	 */
	INTEGRAL_UNFREEZE(TRADE_TYPE_INTEGRAL_UNFREEZE, FROZEN_TO_ACTIVE),
	/**
	 * 申请积分提现
	 */
	INTEGRAL_CASH_APPLY(TRADE_TYPE_INTEGRAL_CASH_APPLY, ACTIVE_TO_FROZEN),
	/**
	 * 提现成功(扣除冻结的提现积分)
	 */
	INTEGRAL_CASH_TRUE(TRADE_TYPE_INTEGRAL_CASH_TRUE, DEDUCT_FROZEN),
	/**
	 * 提现失败(解冻提现积分)
	 */
	INTEGRAL_CASH_FALSE(TRADE_TYPE_INTEGRAL_CASH_FALSE, FROZEN_TO_ACTIVE),
	/** 第三方提现先成功->后失败（银行回退） */
	INTEGRAL_CASH_BACK(TRADE_TYPE_INTEGRAL_CASH_BACK, ADD_ACTIVE),
	/** 推广员积分收益 */
	INTEGRAL_REWARD_AGENT(TRADE_TYPE_REWARD_AGENT, anchorIncomeCore, true),
	/** 主播积分奖励 */
	INTEGRAL_REWARD_USER(TRADE_TYPE_REWARD_USER, anchorIncomeCore, true),
	/** 速配奖励 */
	INTEGRAL_REWARD_SPEED_DATING(TRADE_TYPE_REWARD_SPEED_DATING, anchorIncomeCore, true),
	/** 邀请积分收益 (人工审核后直接发放，无效冻结) */
	INTEGRAL_INVITE_GAIN(TRADE_TYPE_INTEGRAL_INVITE_GAIN, ADD_ACTIVE),
	/** 考核奖励 (人工审核后直接发放，无效冻结) */
	INTEGRAL_REWARD_ASSESS(TRADE_TYPE_INTEGRAL_REWARD_ASSESS, ADD_ACTIVE),

	/** 后台赠送积分 */
	INTEGRAL_SYSTEM_FREE(TRADE_TYPE_INTEGRAL_SYSTEM_FREE, ADD_ACTIVE),
	/** 后台减少活动积分 */
	INTEGRAL_SYSTEM_DEDUCT(TRADE_TYPE_INTEGRAL_SYSTEM_DEDUCT, DEDUCT_ACTIVE),

	/**
	 * 积分兑换钻石
	 */
	INTEGRAL_EX_COIN(TRADE_TYPE_INTEGRAL_EXCHANGE_COIN, DEDUCT_ACTIVE),
	/** 活跃任务奖励 */
	INTEGRAL_ACTIVE_TASK_REWARD(TRADE_TYPE_INTEGRAL_ACTIVE_TASK_REWARD, ADD_ACTIVE),
	/** 收益任务奖励 */
	INTEGRAL_INCOME_TASK_REWARD(TRADE_TYPE_INTEGRAL_INCOME_TASK_REWARD, ADD_ACTIVE),
	/** 视频任务奖励 */
	INTEGRAL_VIDEO_TASK_REWARD(TRADE_TYPE_INTEGRAL_VIDEO_TASK_REWARD, ADD_ACTIVE),
	/** 视频互动奖励 */
	INTEGRAL_CONT_VIDEO_REWARD(TRADE_TYPE_INTEGRAL_CONT_VIDEO_REWARD, ADD_ACTIVE),
	//
	;
	final TradeTypeCore from;
	/** 表示对应的接收人账户也会有变动（多数是积分入账） */
	final TradeTypeCore to;
	/** 该枚举类型表示钻石交易 还是 积分交易 ？ */
	final boolean forCoinOrIntegral;
	/** 是否优先扣除本金，用于有额外资金情况 */
	final CoinConsumePriority coinConsumePriority;
	/** 有些交易还需要调用其他的微服务，调用可能失败，因此可能需要确认结果。如果未确认，还需要有重试等补偿机制 */
	final boolean handleToConfirm;
	final State state;
	final ValueProxy<TradeType, String> proxy;
	final String i18nKey;
	@EnumValue
	final String value;

	TradeType(String label, State state, TradeTypeCore from, TradeTypeCore to, CoinConsumePriority coinConsumePriority, boolean handleToConfirm) {
		this.from = from;
		this.to = to;
		this.state = state;
		this.forCoinOrIntegral = name().startsWith("COIN_");
		Assert.isTrue(this.forCoinOrIntegral || name().startsWith("INTEGRAL_"), "枚举名称必须以 COIN_ 或 INTEGRAL_ 开头！");
		i18nKey = to == null ? null : "integral.income.from." + StringUtils.removeStart(name(), "COIN_FOR_").replace('_', '.').toLowerCase();
		if (coinConsumePriority == null && forCoinOrIntegral && from.isConsume()) {
			// 目前所有钻石支出操作都是先扣除充值钻石，再扣除活动钻石
			coinConsumePriority = CoinConsumePriority.ACTIVE_FIRST;
		}
		this.handleToConfirm = handleToConfirm;
		this.coinConsumePriority = coinConsumePriority;
		this.value = name();
		this.proxy = new ValueProxy<>(this, state, this.value, label);
	}

	TradeType(String label, TradeTypeCore from) {
		this(label, from, false);
	}

	TradeType(String label, TradeTypeCore from, TradeTypeCore to, CoinConsumePriority coinConsumePriority) {
		this(label, PUBLIC, from, to, coinConsumePriority, false);
	}

	TradeType(String label, TradeTypeCore from, TradeTypeCore to) {
		this(label, PUBLIC, from, to, null, false);
	}

	TradeType(String label, TradeTypeCore from, CoinConsumePriority coinConsumePriority) {
		this(label, from, coinConsumePriority, false);
	}

	TradeType(String label, TradeTypeCore from, CoinConsumePriority coinConsumePriority, boolean handleToConfirm) {
		this(label, PUBLIC, from, null, coinConsumePriority, handleToConfirm);
	}

	TradeType(String label, TradeTypeCore from, boolean handleToConfirm) {
		this(label, PUBLIC, from, null, null, handleToConfirm);
	}

	public boolean isEnabled() {
		return getState() == PUBLIC;
	}

	public TradeTypeCore getCoreType(boolean fromOrTo) {
		return fromOrTo ? from : to;
	}

	public TradeTypeCore getCoreType(Integer side) {
		return getCoreType(Side.FROM.eq(side));
	}

	public static TradeType of(String value) {
		return COIN_RECHARGE.getValueOf(value);
	}

	public static TradeType[] getValues() {
		return ValueProxy.getCachedArray(TradeType.class, TradeType::values);
	}

	private static TradeType[] coinTypes;

	private static TradeType[] integralTypes;

	public static final Set<TradeType> REWARD = Set.of(INTEGRAL_REWARD_AGENT, INTEGRAL_REWARD_USER, INTEGRAL_REWARD_SPEED_DATING, INTEGRAL_INVITE_GAIN, INTEGRAL_REWARD_ASSESS, INTEGRAL_SYSTEM_FREE);

	/** 积分收益类型 */
	public static final TradeType[] INCOME_INTEGRAL_TYPES = { INTEGRAL_GAIN, INTEGRAL_GAIN_EXTRACT_USER, INTEGRAL_REWARD_AGENT, INTEGRAL_REWARD_USER, INTEGRAL_REWARD_SPEED_DATING, INTEGRAL_INVITE_GAIN, INTEGRAL_REWARD_ASSESS };

	public static final Map<String, String> consumeCoinType = new HashMap<>(16);

	static {
		consumeCoinType.put("COIN_FOR_ACTIVITY", "活动");
		consumeCoinType.put("COIN_FOR_GREET", "搭讪");
		consumeCoinType.put("COIN_FOR_MSG", "聊天");
		consumeCoinType.put("COIN_FOR_AUDIO", "语音");
		consumeCoinType.put("COIN_FOR_VIDEO", "视频");
		consumeCoinType.put("COIN_FOR_GIFT", "礼物");
		consumeCoinType.put("COIN_FOR_GIFT_LIVE", "直播礼物");
		consumeCoinType.put("COIN_FOR_RED_PACKET", "发红包");
		consumeCoinType.put("COIN_FOR_DONATE", "打赏");
		consumeCoinType.put("COIN_FOR_GIFT_BAG", "背包礼物");
		consumeCoinType.put("INTEGRAL_SYSTEM_FREE", "赠送");
	}

	public static final TradeType[] PAY_COIN_TYPES = Arrays.stream(getCoinTypes()).filter(c -> c.getFrom().isConsume()).toArray(TradeType[]::new);

	/** 积分解冻类型 */
	public static TradeType[] freezeTypes = { INTEGRAL_GAIN, INTEGRAL_GAIN_EXTRACT_USER, INTEGRAL_REWARD_AGENT, INTEGRAL_REWARD_USER };

	public static TradeType[] getCoinTypes() {
		TradeType[] types = coinTypes;
		if (types == null) {
			coinTypes = types = Arrays.stream(getValues()).filter(TradeType::isForCoinOrIntegral).toArray(TradeType[]::new);
		}
		return types;
	}

	public static TradeType[] getIntegralTypes() {
		TradeType[] types = integralTypes;
		if (types == null) {
			integralTypes = types = Arrays.stream(getValues()).filter(c -> !c.forCoinOrIntegral).toArray(TradeType[]::new);
		}
		return types;
	}

	public static boolean isCashType(TradeType tradeType) {
		return INTEGRAL_CASH_APPLY == tradeType || INTEGRAL_CASH_FALSE == tradeType || INTEGRAL_CASH_TRUE == tradeType;
	}

}
